package com.liruo.idworker.util;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;

/**
 *
 * @Author:liruo
 * @Date:2023-02-05-17:42:51
 * @Desc   返回指定zone的时间戳和时间
 *
 * 时间戳
 * 很多方法都注释了表明返回UTC时间: Instant的toEpochMilli, getEpochSecond
 * toEpochSecond 注释中表明返回UTC时间，并且当前对象时间-ZoneOffset
 *      ZonedDateTime: 当前时区是Asia/Shanghai +8区(ZoneOffset), 因此在toEpochSecond会-8h
 *      LocalDateTime可以指定ZoneOffset, 如果需要当前对象时间，就指定为UTC即-
 *
 * 时间字符串
 * 使用DateTimeFormatter的pattern和zone格式化，DateTimeFormatter没有zone就使用date自己的
 * DateTimeFormatter.formatter和时间对象自己的formatter方法是一样的结果
 *
 * 时间转换
 * LocalDateTime的toInstant要一个ZoneOffset，也是表示要减去ZoneOffset(有正有负)的时间, ofInstant则是加上
 *      像ZonedDateTime，OffsetDateTime这样的无参toInstant就不行，会创建UTC的Instant
 *      因为ZonedDateTime，OffsetDateTime会自动减去时差变为UTC
 * Date.from(instant)仅仅把毫秒放到date里而已，和创建Date放System.currentTimeMillis
 *      他的toString之所以可以转为系统时间是因为在里面调用了normalize方法使用TimeZone.getDefaultRef()获取时间
 * Instant只是固定用UTC表示
 *      Instant要想指定时区就用atZone方法,atOffset也可以
 *
 *
 * 解析:
 *   同时区解析
 *   指定时区解析--使用ZonedDateTime可以指定为formatter的时区，时间不变
 *          也可以传入ZonedDateTime的格式 2023-02-05T20:20:26+08:00[Asia/Shanghai]
 *          如果需要转为本地时间使用ZonedDateTime的withZoneSameInstant
 */
@Deprecated
public class TimeUtils {
    private final static ZoneId DEFAULT = TimeZone.getDefault().toZoneId();
    private static ZoneId currentZone  = DEFAULT;
    private static ZoneOffset currentZoneOffset  = ZoneIdToOffset(currentZone);

    private static String PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static DateTimeFormatter dateTimeFormatter =
            DateTimeFormatter
                    .ofPattern(PATTERN)
                    .withZone(currentZone);
    private static ZoneOffset ZoneIdToOffset(ZoneId zoneId){
        return zoneId.getRules().getOffset(Instant.now());
    }


    //修改zone

    public static void changeZone(int offset){
        ZoneOffset newZone = ZoneOffset.ofHours(offset);
        currentZone = newZone;
        currentZoneOffset = newZone;
        dateTimeFormatter = dateTimeFormatter.withZone(currentZone);
    }
    public static void changeZone(ZoneId zoneId){
        currentZone = zoneId;
        currentZoneOffset  = zoneId.getRules().getOffset(Instant.now());
        dateTimeFormatter = dateTimeFormatter.withZone(currentZone);
    }
    public static void changeDateTimeFormatter(String pattern){
        PATTERN = pattern;
        dateTimeFormatter = DateTimeFormatter
                .ofPattern(pattern)
                .withZone(currentZone);
    }


    public static String getDateTimeFormatterPattern(){
        return PATTERN;
    }
    public static String currentZone() {
        return "currentZone=[" + currentZone.getId() + ": " + currentZoneOffset.getId() + "]";
    }

    public static Instant nowInstant(){
        return Instant.now().plusSeconds(currentZoneOffset.getTotalSeconds());
    }


    //时间戳

    public static long nowSecond(){
        return instantSecond(Instant.now());
    }
    public static long instantSecond(Instant instant){
        return instant.plusSeconds(currentZoneOffset.getTotalSeconds()).getEpochSecond();
    }

    public static long nowSecond(ZoneId zoneId){
        return nowSecond(ZoneIdToOffset(zoneId));
    }
    public static long nowSecond(ZoneOffset zoneOffset){
        return Instant.now().plusSeconds(zoneOffset.getTotalSeconds()).getEpochSecond();
    }

    public static long millis(Instant instant){
        return instant.plusSeconds(currentZoneOffset.getTotalSeconds()).toEpochMilli();
    }

    /**
     * @return  UTC timestamp--默认减去系统的，除非临时修改一下zone
     */
    public static long millis(LocalDateTime localDateTime){
        return millis(localDateTime.toInstant(currentZoneOffset));
    }
    /**
     * @return  UTC timestamp--，date修改不了，其getTime是默认减去系统的
     */
    public static long millis(Date date){
        return millis(date.toInstant());
    }



    public static long seconds(Instant instant){
        return instant.plusSeconds(currentZoneOffset.getTotalSeconds()).getEpochSecond();
    }

    /**
     * @return  UTC timestamp--默认减去系统的，除非临时修改一下zone
     */
    public static long seconds(LocalDateTime localDateTime){
        return seconds(localDateTime.toInstant(currentZoneOffset));
    }
    /**
     * @return  UTC timestamp--，date修改不了，其getTime是默认减去系统的
     */
    public static long seconds(Date date){
        return seconds(date.toInstant());
    }

    public static long nowMillis(){
        return millis(Instant.now());
    }
    public static long nowMillis(ZoneId zoneId){
        return nowMillis(ZoneIdToOffset(zoneId));
    }
    public static long nowMillis(ZoneOffset zoneOffset){
        return Instant.now().plusSeconds(zoneOffset.getTotalSeconds()).toEpochMilli();
    }

    //解析时间戳

    public static Instant ofMillis(long millis){
        return Instant.ofEpochMilli(millis);
    }
    public static Instant ofSecond(long second){
        return Instant.ofEpochSecond(second);
    }


    //时间字符串
    public static String format(LocalDateTime localDateTime){
        return localDateTime.format(dateTimeFormatter);
    }
    public static String format(ZonedDateTime zonedDateTime){
        return zonedDateTime.format(dateTimeFormatter);
    }
    public static String format(Date date){
        return toLocalDateTime(date).format(dateTimeFormatter);
    }
    public static String format(Instant instant){
        return format(toLocalDateTime(instant));
    }
    public static String format(long timestamp){
        return format(new Date(timestamp));
    }

    //解析时间字符串

    /**
     * @param datetime  使用ZonedDateTime的格式 2023-02-05T20:20:26+08:00[Asia/Shanghai]
     * @return null返回ZonedDateTime
     */
    public static <T> T parseWithZone(String datetime, Class<T> clazz){
        return transformTo(clazz, ZonedDateTime.parse(datetime));
    }


    /**
     * @param datetime  使用ZonedDateTime的格式 2023-02-05T20:20:26+08:00[Asia/Shanghai]
     *                   把其他时区的时间本地化
     * @return null返回ZonedDateTime
     */
    public static <T> T parseWithZoneLocalize(String datetime, Class<T> clazz){
        return transformTo(clazz, ZonedDateTime.parse(datetime).withZoneSameInstant(currentZone));
    }

    /**
     * @param datetime 使用指定的pattern，转为dateTimeFormatter的时区即当前时区
     * @return
     */
    public static <T> T parse(String datetime, Class<T> clazz){
        return transformTo(clazz, ZonedDateTime.parse(datetime, dateTimeFormatter));
    }
    @SuppressWarnings("unchecked")
    private static <T> T transformTo(Class<T> clazz, ZonedDateTime zonedDateTime) {
        if(clazz == null){
            return (T) zonedDateTime;
        }else if(LocalDateTime.class.isAssignableFrom(clazz)){
            return (T) zonedDateTime.toLocalDateTime();
        }else if(Date.class.isAssignableFrom(clazz)){
            return (T) toDate(zonedDateTime.toLocalDateTime());
        }else if(Instant.class.isAssignableFrom(clazz)){
            return (T) zonedDateTime.toInstant();
        }
        throw new RuntimeException("class not match");
    }





    //转换

    /**
     * Date转LocalDateTime
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return date.toInstant().atZone(currentZone).toLocalDateTime();
    }
    public static LocalDateTime toLocalDateTime(Instant instant) {
        return  LocalDateTime.ofInstant(instant, currentZone);
    }

    /**
     * 转Date   仅仅是将UTC毫秒数传给Date的构造函数
     * @param localDateTime LocalDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(currentZone).toInstant());
    }
    public static Date toDate(Instant instant) {
        return Date.from(instant);
    }
}
